﻿using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace mqmake
{
    public class ProjectParser
    {
        public const string VERSION = "1.0.0";
        public string Name { get; set; }
        public ToolChain toolchain = new ToolChain();
        public string OutPath;
        public bool IsCreateBin = false;
        public bool IsCreateHex = false;
        public string LDFile;
        public string ASFlag;
        public string CCFlag;
        public string LDFlag;
        List<string> Includes = new List<string>();
        public string LibPath;
        public string LibFile;
        List<string> SrcList = new List<string>();

        public string CCParam
        {
            get
            {
                return string.Format("{0} {1}", CCFlag, string.Join(" ", Includes));
            }
        }

        public string Target
        {
            get { return OutPath + Name + ".elf"; }
        }


        public ProjectParser(string filename)
        {
            if (File.Exists(filename))
            {
                JObject jo = (JObject)JsonConvert.DeserializeObject(File.ReadAllText(filename));
                if ((jo["version"] == null ? "" : jo["version"].ToString()) == VERSION)//判断版本一致
                {
                    Name = jo["name"] == null ? "" : jo["name"].ToString();
                    //工具链解析
                    if (jo["toolchain"] != null)
                    {
                        string path = jo["toolchain"]["path"] == null ? "" : jo["toolchain"]["path"].ToString();
                        string prefix = jo["toolchain"]["prefix"] == null ? "" : jo["toolchain"]["prefix"].ToString();
                        toolchain.AS = jo["toolchain"]["as"] == null ? "" : string.Format("{0}{1}{2}", path, prefix, jo["toolchain"]["as"]);
                        toolchain.CC = jo["toolchain"]["cc"] == null ? "" : string.Format("{0}{1}{2}", path, prefix, jo["toolchain"]["cc"]);
                        toolchain.LD = jo["toolchain"]["ld"] == null ? "" : string.Format("{0}{1}{2}", path, prefix, jo["toolchain"]["ld"]);
                        toolchain.OBJCOPY = jo["toolchain"]["objcopy"] == null ? "" : string.Format("{0}{1}{2}", path, prefix, jo["toolchain"]["objcopy"]);
                    }
                    //参数解析
                    if (jo["flag"] != null)
                    {
                        ASFlag = jo["flag"]["as"] == null ? "" : jo["flag"]["as"].ToString();
                        CCFlag = jo["flag"]["cc"] == null ? "" : jo["flag"]["cc"].ToString();
                        LDFlag = jo["flag"]["ld"] == null ? "" : jo["flag"]["ld"].ToString();

                    }
                    //输出解析
                    if (jo["output"] != null)
                    {
                        OutPath = jo["output"]["path"] == null ? "" : jo["output"]["path"].ToString();
                        IsCreateBin = jo["output"]["bin"] == null ? false : (bool)jo["output"]["bin"];
                        IsCreateHex = jo["output"]["hex"] == null ? false : (bool)jo["output"]["hex"];
                    }
                    //链接文件
                    if (jo["ldfile"] != null)
                    {
                        LDFile = jo["ldfile"] == null ? "" : jo["ldfile"].ToString();
                    }
                    //头文件路径
                    if (jo["include"] != null)
                    {
                        foreach (JValue item in (JArray)jo["include"])
                        {
                            Includes.Add("-I " + item.ToString());
                        }
                    }
                    //库文件

                    //源文件
                    if (jo["src"] != null)
                    {
                        foreach (JValue item in (JArray)jo["src"])
                        {
                            string partten = item.ToString();
                            try
                            {
                                SrcList.AddRange(Directory.GetFiles(Path.GetDirectoryName(partten), Path.GetFileName(partten)));
                            }
                            catch (Exception)
                            {
                            }
                        }
                    }
                }
            }
        }

        public bool CheckUpdate(string infile)
        {
            string outfile = GetOutFile(infile);
            if (File.Exists(outfile))
            {
                if (File.GetLastWriteTimeUtc(outfile) > File.GetLastWriteTimeUtc(infile))
                {

                }
            }
            return true;
        }

        public string GetCompileCMD(string infile)
        {
            switch (Path.GetExtension(infile))
            {
                case ".c":
                case ".C":
                    return string.Format("{0} -o {1} -c {2} {3} {4}", toolchain.CC, GetOutFile(infile), infile, CCFlag, string.Join(" ", Includes));
                case ".s":
                case ".S":
                    return string.Format("{0} -o {1} -c {2} {3}", toolchain.AS, GetOutFile(infile), infile, ASFlag);
                default:
                    return string.Format("{0} -o {1} -c {2} {3} ", toolchain.CC, GetOutFile(infile), infile, CCFlag);
            }

        }

        private string GetOutFile(string infile)
        {
            return Path.ChangeExtension(OutPath + Path.GetFileName(infile), "o");
        }

        public List<string> GetTasks()
        {
            List<string> TaskList = new List<string>();
            foreach (string item in SrcList)
            {
                if (CheckUpdate(item))
                {
                    TaskList.Add(GetCompileCMD(item));
                }
            }
            return TaskList;
        }

        public string GetLinkCMD()
        {
            return string.Format("{0} {1} -o {2} {3}", toolchain.LD, string.Join(" ", Directory.GetFiles(OutPath, "*.o")), Target, LDFlag + " -Tld/stm32_flash.ld");
        }

        public class ToolChain
        {
            public string CC;
            public string AS;
            public string LD;
            public string OBJCOPY;
        }
    }
}
